// User Service - 用户认证与权限管理

use axum::{
    extract::{Json, Path, State},
    http::StatusCode,
    routing::{get, post, patch},
    Router,
};
use common::{ApiResponse, UserRole};
use redis::AsyncCommands;
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use std::sync::Arc;
use auth::AuthUser;

// ========== 数据模型 ==========

#[derive(Debug, Serialize, Deserialize, sqlx::FromRow)]
struct User {
    id: String,
    phone: String,
    name: String,
    role: String,
    status: String,
    created_at: chrono::DateTime<chrono::Utc>,
}

// ========== API 请求/响应 ==========

#[derive(Debug, Deserialize)]
struct RegisterRequest {
    phone: String,
    password: String,
    name: String,
    role: UserRole,
}

#[derive(Debug, Serialize)]
struct RegisterResponse {
    user_id: String,
    message: String,
}

#[derive(Debug, Deserialize)]
struct LoginRequest {
    phone: String,
    password: String,
}

#[derive(Debug, Serialize)]
struct LoginResponse {
    access_token: String,
    refresh_token: String,
    user: UserInfo,
}

#[derive(Debug, Serialize)]
struct UserInfo {
    id: String,
    name: String,
    role: UserRole,
}

#[derive(Debug, Deserialize)]
struct RefreshTokenRequest {
    refresh_token: String,
}

#[derive(Debug, Serialize)]
struct RefreshTokenResponse {
    access_token: String,
}

#[derive(Debug, Deserialize)]
struct ReviewUserRequest {
    status: String, // "approved" or "rejected"
    reason: Option<String>,
}

// ========== 应用状态 ==========

#[derive(Clone)]
struct AppState {
    db: PgPool,
    jwt_secret: String,
    redis: redis::aio::ConnectionManager,
}

// ========== 处理器 ==========

/// 健康检查
async fn health_check() -> (StatusCode, Json<ApiResponse<String>>) {
    (StatusCode::OK, Json(ApiResponse::ok("OK".to_string())))
}

/// 用户注册
async fn register(
    State(state): State<Arc<AppState>>,
    Json(req): Json<RegisterRequest>,
) -> (StatusCode, Json<ApiResponse<RegisterResponse>>) {
    // 验证手机号格式
    if !req.phone.len() == 11 {
        return (
            StatusCode::BAD_REQUEST,
            Json(ApiResponse::error("手机号格式不正确")),
        );
    }

    // 检查手机号是否已注册
    let existing = sqlx::query_as::<_, User>(
        "SELECT * FROM users WHERE phone = $1"
    )
    .bind(&req.phone)
    .fetch_optional(&state.db)
    .await;

    if let Ok(Some(_)) = existing {
        return (
            StatusCode::CONFLICT,
            Json(ApiResponse::error("手机号已注册")),
        );
    }

    // 哈希密码
    let password_hash = match auth::hash_password(&req.password) {
        Ok(hash) => hash,
        Err(_) => {
            return (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(ApiResponse::error("密码处理失败")),
            );
        }
    };

    // 创建用户
    let user_id = common::generate_id();
    let role_str = format!("{:?}", req.role).to_lowercase();

    let result = sqlx::query(
        r#"
        INSERT INTO users (id, phone, password_hash, name, role, status, created_at)
        VALUES ($1, $2, $3, $4, $5, 'pending', NOW())
        "#,
    )
    .bind(&user_id)
    .bind(&req.phone)
    .bind(&password_hash)
    .bind(&req.name)
    .bind(&role_str)
    .execute(&state.db)
    .await;

    match result {
        Ok(_) => {
            tracing::info!("User registered: {}", user_id);
            (
                StatusCode::CREATED,
                Json(ApiResponse::ok(RegisterResponse {
                    user_id,
                    message: "注册成功，请等待审核".to_string(),
                })),
            )
        }
        Err(e) => {
            tracing::error!("Registration failed: {}", e);
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(ApiResponse::error("注册失败")),
            )
        }
    }
}

/// 用户登录（含限流和审计）
async fn login(
    State(state): State<Arc<AppState>>,
    Json(req): Json<LoginRequest>,
) -> (StatusCode, Json<ApiResponse<LoginResponse>>) {
    let mut redis_conn = state.redis.clone();
    
    // 1. 检查登录失败次数（限流）
    let rate_limit_key = format!("login_fail:{}", req.phone);
    let fail_count: i32 = redis_conn
        .get(&rate_limit_key)
        .await
        .unwrap_or(0);
    
    if fail_count >= 5 {
        tracing::warn!("Login rate limited: {}", req.phone);
        // 记录审计日志
        log_audit(&state.db, "login_rate_limited", &req.phone, &format!("登录失败次数过多，锁定5分钟")).await;
        return (
            StatusCode::TOO_MANY_REQUESTS,
            Json(ApiResponse::error("登录失败次数过多，请5分钟后重试")),
        );
    }

    // 2. 查询用户
    let user = sqlx::query_as::<_, User>(
        "SELECT * FROM users WHERE phone = $1"
    )
    .bind(&req.phone)
    .fetch_optional(&state.db)
    .await;

    let user = match user {
        Ok(Some(u)) => u,
        _ => {
            // 登录失败，增加计数
            let _: Result<(), _> = redis_conn.incr(&rate_limit_key, 1).await;
            let _: Result<(), _> = redis_conn.expire(&rate_limit_key, 300).await; // 5分钟过期
            
            log_audit(&state.db, "login_failed", &req.phone, "用户不存在").await;
            return (
                StatusCode::UNAUTHORIZED,
                Json(ApiResponse::error("用户名或密码错误")),
            );
        }
    };

    // 3. 验证密码
    let password_hash = sqlx::query_scalar::<_, String>(
        "SELECT password_hash FROM users WHERE id = $1"
    )
    .bind(&user.id)
    .fetch_one(&state.db)
    .await
    .unwrap_or_default();

    let is_valid = auth::verify_password(&req.password, &password_hash)
        .unwrap_or(false);

    if !is_valid {
        // 登录失败，增加计数
        let _: Result<(), _> = redis_conn.incr(&rate_limit_key, 1).await;
        let _: Result<(), _> = redis_conn.expire(&rate_limit_key, 300).await; // 5分钟过期
        
        log_audit(&state.db, "login_failed", &req.phone, "密码错误").await;
        return (
            StatusCode::UNAUTHORIZED,
            Json(ApiResponse::error("用户名或密码错误")),
        );
    }
    
    // 登录成功，清除失败计数
    let _: Result<(), _> = redis_conn.del(&rate_limit_key).await;

    // 检查账号状态
    if user.status != "approved" {
        return (
            StatusCode::FORBIDDEN,
            Json(ApiResponse::error("账号未审核或已禁用")),
        );
    }

    // 生成 JWT Token
    let role: UserRole = match user.role.as_str() {
        "teacher" => UserRole::Teacher,
        "student" => UserRole::Student,
        "parent" => UserRole::Parent,
        "admin" => UserRole::Admin,
        _ => UserRole::Student,
    };

    let access_token = auth::generate_token(&user.id, role, &state.jwt_secret, 2)
        .unwrap_or_default();
    let refresh_token = auth::generate_token(&user.id, role, &state.jwt_secret, 168)
        .unwrap_or_default();

    // 记录审计日志
    log_audit(&state.db, "login_success", &user.id, &format!("用户 {} 登录成功", user.name)).await;
    tracing::info!("User logged in: {}", user.id);

    (
        StatusCode::OK,
        Json(ApiResponse::ok(LoginResponse {
            access_token,
            refresh_token,
            user: UserInfo {
                id: user.id.clone(),
                name: user.name,
                role,
            },
        })),
    )
}

/// 刷新访问令牌
async fn refresh_token(
    State(state): State<Arc<AppState>>,
    Json(req): Json<RefreshTokenRequest>,
) -> (StatusCode, Json<ApiResponse<RefreshTokenResponse>>) {
    // 验证 refresh token
    let claims = match auth::verify_token(&req.refresh_token, &state.jwt_secret) {
        Ok(c) => c,
        Err(_) => {
            return (
                StatusCode::UNAUTHORIZED,
                Json(ApiResponse::error("Invalid or expired refresh token")),
            );
        }
    };

    // 检查用户是否仍然有效
    let user = sqlx::query_as::<_, User>("SELECT * FROM users WHERE id = $1 AND status = 'approved'")
        .bind(&claims.sub)
        .fetch_optional(&state.db)
        .await;

    if user.is_err() || user.unwrap().is_none() {
        return (
            StatusCode::UNAUTHORIZED,
            Json(ApiResponse::error("User not found or not approved")),
        );
    }

    // 生成新的 access token
    let access_token = auth::generate_token(&claims.sub, claims.role, &state.jwt_secret, 2)
        .unwrap_or_default();

    (
        StatusCode::OK,
        Json(ApiResponse::ok(RefreshTokenResponse { access_token })),
    )
}

/// 审核用户（仅管理员）
async fn review_user(
    auth_user: AuthUser,
    State(state): State<Arc<AppState>>,
    Path(user_id): Path<String>,
    Json(req): Json<ReviewUserRequest>,
) -> (StatusCode, Json<ApiResponse<String>>) {
    // 检查是否为管理员
    if let Err(_) = auth::require_role(&auth_user, &[UserRole::Admin]) {
        return (
            StatusCode::FORBIDDEN,
            Json(ApiResponse::error("仅管理员可以审核用户")),
        );
    }

    // 验证状态值
    if req.status != "approved" && req.status != "rejected" {
        return (
            StatusCode::BAD_REQUEST,
            Json(ApiResponse::error("状态值必须是 approved 或 rejected")),
        );
    }

    // 更新用户状态
    let result = sqlx::query(
        "UPDATE users SET status = $1, updated_at = NOW() WHERE id = $2 AND status = 'pending'"
    )
    .bind(&req.status)
    .bind(&user_id)
    .execute(&state.db)
    .await;

    match result {
        Ok(r) if r.rows_affected() > 0 => {
            tracing::info!("User {} reviewed by admin {}: {}", user_id, auth_user.user_id, req.status);
            (
                StatusCode::OK,
                Json(ApiResponse::ok(format!("用户审核成功: {}", req.status))),
            )
        }
        Ok(_) => (
            StatusCode::NOT_FOUND,
            Json(ApiResponse::error("用户不存在或已审核")),
        ),
        Err(e) => {
            tracing::error!("User review failed: {}", e);
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(ApiResponse::error("审核失败")),
            )
        }
    }
}

/// 获取待审核用户列表（仅管理员）
async fn list_pending_users(
    auth_user: AuthUser,
    State(state): State<Arc<AppState>>,
) -> (StatusCode, Json<ApiResponse<Vec<User>>>) {
    // 检查是否为管理员
    if let Err(_) = auth::require_role(&auth_user, &[UserRole::Admin]) {
        return (
            StatusCode::FORBIDDEN,
            Json(ApiResponse::error("仅管理员可以查看待审核用户")),
        );
    }

    // 查询待审核用户
    let users = sqlx::query_as::<_, User>(
        "SELECT id, phone, name, role, status, created_at FROM users WHERE status = 'pending' ORDER BY created_at DESC"
    )
    .fetch_all(&state.db)
    .await;

    match users {
        Ok(users) => (StatusCode::OK, Json(ApiResponse::ok(users))),
        Err(e) => {
            tracing::error!("Failed to fetch pending users: {}", e);
            (
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(ApiResponse::error("查询失败")),
            )
        }
    }
}

/// 获取当前用户信息（受保护路由）
async fn get_profile(
    auth_user: AuthUser,
    State(state): State<Arc<AppState>>,
) -> (StatusCode, Json<ApiResponse<User>>) {
    let user = sqlx::query_as::<_, User>(
        "SELECT id, phone, name, role, status, created_at FROM users WHERE id = $1"
    )
    .bind(&auth_user.user_id)
    .fetch_optional(&state.db)
    .await;

    match user {
        Ok(Some(user)) => (StatusCode::OK, Json(ApiResponse::ok(user))),
        _ => (
            StatusCode::NOT_FOUND,
            Json(ApiResponse::error("用户不存在")),
        ),
    }
}

/// 用户登出（将令牌加入黑名单）
async fn logout(
    auth_user: AuthUser,
    State(state): State<Arc<AppState>>,
    Json(req): Json<RefreshTokenRequest>,
) -> (StatusCode, Json<ApiResponse<String>>) {
    let mut redis_conn = state.redis.clone();
    
    // 将 access_token 加入黑名单（2小时过期）
    let blacklist_key = format!("token:blacklist:{}", req.refresh_token);
    let _: Result<(), _> = redis_conn.set_ex(&blacklist_key, "1", 7200).await;
    
    // 记录审计日志
    log_audit(&state.db, "logout", &auth_user.user_id, "用户登出").await;
    
    tracing::info!("User logged out: {}", auth_user.user_id);
    (StatusCode::OK, Json(ApiResponse::ok("登出成功".to_string())))
}

// ========== 辅助函数 ==========

/// 记录审计日志（异步，不影响主流程）
async fn log_audit(db: &PgPool, action: &str, user_id: &str, details: &str) {
    let result = sqlx::query(
        r#"
        INSERT INTO audit_logs (action, user_id, details, created_at)
        VALUES ($1, $2, $3, NOW())
        "#
    )
    .bind(action)
    .bind(user_id)
    .bind(details)
    .execute(db)
    .await;
    
    if let Err(e) = result {
        tracing::error!("Failed to log audit: {}", e);
    }
}

// ========== 主函数 ==========

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    use common::service::*;
    
    init_tracing();
    dotenvy::dotenv().ok();

    let db = init_db("DATABASE_URL", "postgresql://intelligrade:password@localhost:5432/intelligrade").await?;
    let redis_client = redis::Client::open(env_or("REDIS_URL", "redis://localhost:6379"))?;
    let redis = redis::aio::ConnectionManager::new(redis_client).await?;
    tracing::info!("Redis connected");

    let state = Arc::new(AppState { 
        db, 
        jwt_secret: env_or("JWT_SECRET", "your_secret_key"), 
        redis 
    });

    let app = Router::new()
        .route("/health", get(health_check))
        .route("/api/v1/auth/register", post(register))
        .route("/api/v1/auth/login", post(login))
        .route("/api/v1/auth/refresh", post(refresh_token))
        .route("/api/v1/auth/logout", post(logout))
        .route("/api/v1/users/profile", get(get_profile))
        .route("/api/v1/admin/users/pending", get(list_pending_users))
        .route("/api/v1/admin/users/:user_id/review", patch(review_user))
        .with_state(state);

    start_service("User service", &env_or("USER_SERVICE_PORT", "8081"), app).await
}
